Skop vaj, pri katerih uporabljamo sezname
V Republiki Banana zaradi utrujenosti in pomanjkanja koncentracije kamionisti (pet minut za učenje slovenčine) vse pogosteje povzročajo nesreče. Na vladi so se odločili, da bodo sprejeli zakone, ki bodo uredili problematiko preutrujenih kamionistov. Najprej pa morajo analitiki preučiti njihove navade. V ta namen so pridobili podatke o kamionistih. Za vsakega imajo podan seznam, v katerem so shranjene prevožene razdalje po posameznih dnevih. Število 0 pomeni, da je kamionist tisti dan počival. Na primer seznam
[350, 542.5, 0, 602, 452.5, 590.5, 0, 248]
pomeni, da je kamionist prvi dan prevozil 350 km, drugi dan je prevozil 542.5 km, tretji dan je počival itd.
Sestavite funkcijo pocitekInPovprecje(voznja)
, ki kot argument
dobi zgoraj opisani seznam (prevožene razdalje po posameznih dnevih)
in vrne par števil. Prvo število naj bo število dni, ko je kamionist
počival. Drugo število naj bo na eno decimalko zaokrožena
povprečna dnevna prevožena razdalja, pri
čemer upoštevamo samo tiste dneve, ko ni počival. Predpostavite lahko,
da kamionist vsaj en dan ni počival. Primer:
>>> pocitekInPovprecje([200, 300, 0, 100])
(1, 200.0)
Kamionist je torej enkrat počival. Ob dnevih, ko ni počival, pa je v povprečju prevozil 200 km.
def pocitekInPovprecje(voznja): '''Vrne par števil. Prvo pove število dni, ko kamionist počiva in drugo povprečno št. kilometrov na dneve vožnje ''' stPocitkov = 0 delovnihDni = 0 skupnoKilometrov = 0 for prevozenoTaDan in voznja: if prevozenoTaDan == 0: stPocitkov += 1 else: delovnihDni += 1 skupnoKilometrov += prevozenoTaDan return stPocitkov, round(skupnoKilometrov / delovnihDni, 1) # zaradi predpostavke # zagotovo ne delimo z 0!
Napišite funkcijo primerjaj(prvi, drugi)
, ki primerja vožnjo dveh
kamionistov. Funkcija kot argumenta dobi dva enako dolga seznama
prvi
in drugi
, ki opisujeta vožnjo dveh kamionistov, ki sta se
podala na isto pot. Funkcije naj sestavi in vrne nov seznam, v katerem
je za vsak dan zapisano, kdo je do tega dne skupaj prevozil večjo razdaljo:
1
, če je bil to 1. kamionist; 2
, če je bil to 2. kamionist in
0
, če sta oba prevozila enako razdaljo. Primer:
>>> primerjaj([200, 300, 100], [200, 200, 300])
[0, 1, 2]
>>> primerjaj([500, 100, 100], [100, 200, 200])
[1, 1, 1]
def primerjaj(prvi, drugi): '''Vrne seznam podatkov o tem, kateri kamionist je prišel do določenega dne dlje''' prevozenoPrvi = 0 # skupno število prevoženih kilometrov do določenega dne prevozenoDrugi = 0 primerjava = [] dan = 0 while dan < len(prvi): # uporabimo while, ker potrebujemo podatke iz obeh seznamov prevozenoPrvi += prvi[dan] prevozenoDrugi += drugi[dan] # kdo je v tem trenutku že dlje if prevozenoPrvi > prevozenoDrugi: primerjava.append(1) elif prevozenoPrvi < prevozenoDrugi: primerjava.append(2) else: primerjava.append(0) dan += 1 return primerjava
Vlada je uzakonila naslednja pravila: Povprečna prevožena razdalja v treh zaporednih dneh ne sme biti več kot 500 km. (Štejemo tudi dneve, ko je kamionist počival.) Kamionist ne sme brez počitka voziti več kot 5 dni v zaporedju.
Ker pa so ugotovili, da so kamionisti prevečkrat svoje zaporedje skrajšali na dva dni in se s tem dejansko izognili pravilu, so uzakonili še: Zadnji dan ne sme voziti več kot 500 km. Povprečje zadnjih dveh dni ne sme biti več kot 500 km.
Sestavite funkcijo poPravilih(voznja)
, ki vrne True
, če se je
kamionist držal predpisov, in False
, če se jih ni.
>>> poPravilih([50, 200, 300, 20, 100, 60])
False
>>> poPravilih([600, 200, 0, 300, 300, 0, 600, 600, 400])
False
>>> poPravilih([600, 600, 0, 600, 600])
False
>>> poPravilih([600, 600, 0, 200, 600])
False
def poPravilih(voznja): '''Ali je vožnja potekala po pravilih''' zaporedno = 0 dan = 0 while dan < len(voznja) - 2: # za račun povprečja zaporedja! prevozil = voznja[dan] if prevozil == 0: # je počival, začnemo šteti od začetka zaporedno = 0 else: zaporedno += 1 if zaporedno > 5: # zaporedoma vozi več kot 5 dni return False povprecje = (voznja[dan] + voznja[dan+1] + voznja[dan+2]) / 3 if povprecje > 500: return False dan += 1 # pregledamo še zadnja dva dni while dan < len(voznja): # dan je že ustrezno "velik", torej se bo zanka izvedla 2krat prevozil = voznja[dan] if prevozil == 0: zaporedno = 0 else: zaporedno += 1 if zaporedno > 5: return False dan += 1 # še povprečji # če imamo sploh še 2 dni (če imamo le en podatek+, to ne bo res) if len(voznja) - dan == 2: if (voznja[len(voznja) - 1] + voznja[len(voznja) - 2])/2 > 500: return False # še kontrola dolžine vožnje zadnji dan if voznja[-1] > 500: return False # uspešno preko vseh kontrol return True
Podatke za več kamionistov so analitiki združili v en sam seznam. Zgled takega seznama:
vsiSkupaj = [
[50, 200, 300, 20, 100, 60],
[600, 600, 0, 600, 600, 0, 500, 500],
[600, 200, 0, 300, 300, 0, 600, 600, 400]
]
Sestavite funkcijo preveriVse(seznamVozenj)
, ki dobi kot argument
na tak način opisan seznam in vrne seznam logičnih vrednosti, ki za vsakega kamionista
pove, če je vozil po predpisih. Primer:
>>> preveriVse(vsiSkupaj)
[False, True, False]
def preveriVse(seznamVozenj): '''Preveri vožnje vseh kamionistov''' rezultat = [] for voznjaPosameznika in seznamVozenj: # rezultat.append(poPravilih(voznjaPosameznika)) return rezultat
Ko so vožnje vseh kamionistov že tako lepo združene, so se analitiki spravili
računati še to, kakšno je navečje število voženj, ki jih je nekdo opravil,
kakšno je največje število dni počitka in kakšno največje in kakšno najmanjše povprečno
povprečno število dnevno prevoženih kilometrov (povprečje tako, kot pri prvi
nalogi - štejemo le dneve vožnje). Pri tem upoštevamo samo tiste kamioniste,
ki so vozili po pravilih!
Sestavite funkcijo analitika(seznamVozenj)
, ki dobi kot argument
opisani seznam in vrne nabor 4 vrednosti: največ voženj, največ dni počitka, maksimalno dnevno prevoženih
in minimalno dnevno prevoženih km. Predpostavi, da imamo vsaj enega kamionista, ki je vozil po predpisih!
Primer (podatki iz prejšnje naloge):
>>> analitika(vsiSkupaj)
(6, 2, 566.7, 566.7)
def analitika(seznamVozenj): '''med pravilno vozečimi kamionisti poišče nabor 4 vrednosti: največ voženj, največ dni počitka, maksimalno dnevno prevoženih in minimalno dnevno prevoženih km.''' minPovp = 600 # vsaj en bo vozil po predpisih, torej bo minimalno povprecje zagotovo pod 500! maxPovp = 0 maxPoc = 0 # maksimalno dni počitka maxVozenj = 0 for voznjaPosameznika in seznamVozenj: if poPravilih(voznjaPosameznika): # "dobri" voznik, ga upoštevamo poc, povp = pocitekInPovprecje(voznjaPosameznika) vozenj = len(voznjaPosameznika) - poc # ali so katere od teh vrednosti za "naj" if poc > maxPoc: maxPoc = poc # namesto if, uporabimo raje kar min, oz. max maxVozenj = max(vozenj, maxVozenj) minPovp = min(povp, minPovp) maxPovp = max(povp, maxPovp) return (maxVozenj, maxPoc, maxPovp, minPovp)
Na Najboljši TV je prava zmešnjava (kar za najnovejšo TV v Sloveniji niti ni tako nenavadno). Le še 5 minut do začetka oddaje Izbiramo najlepšega bika Slovenije. Težav pa cel kup.
Prva težava je, da je na vseh seznamih naveden napačni vrstni red imen bikov. Režiser na
vsak način poskuša prepričati voditeljski par, da ni nič narobe, le od spodaj navzgor
naj bereta razvrstitev. A kljub temu, da sta to daleč najbolj inteligentna TV voditelja
v Sloveniji, se bojita, da bo to zanju pretežka naloga.
Zato jim moraš hitro napisati
funkcijo obrniSeznamBikov(sezBik)
, ki vrnila nov seznam teh imen
v obratnem vrstnem redu. Za seznam
['Bukso', 'Hitri', 'Šeko', 'Lisko']
naj vrne seznam
['Lisko', 'Šeko', 'Hitri', 'Bukso']
Pazi, ker moraš vrniti nov seznam, uporabe metode reverse ne bo OK!
def obrniSeznamBikov(sezBik): ''' vrne nov seznam bikov v obratnem vrstnem redu ''' novSez = [] for bik in sezBik: novSez = [bik] + novSez # ker dodajamo spredaj, bomo seznam obrnili return novSez
Seznam bikov je sedaj urejen. A kaj, ko so na seznam prikradle tudi krave (na TV
sumijo, da gre za podtalno delovanje stricev iz ozadja, a ...). In zato se bodo
pritožili na MCSodišče. A ura je neizprosna, ustrezen seznam potrebujejo takoj.
Na srečo je najomiljeni voditelj z vso svojo avtoriteto ugotovil,
da je krave zlahka prepoznati, saj se vsa njihova imena končajo z 'a'.
Ker želijo ohraniti dokaze, morajo seznam s pomešanimi
kravami ohraniti. Zato sestavi
funkcijo odstraniKrave(seznam)
, ki vrnila nov seznam teh imen
brez krav. Biki morajo ohraniti svoj vrstni red. Za seznam
['Liska', 'Šeko', 'Hitri', 'Buksa']
funkcija vrne
['Šeko', 'Hitri']
def odstraniKrave(seznam): ''' vrne nov seznam brez krav (imen, ki se končajo z a) ''' novSez = [] for žival in seznam: if žival[-1] != 'a' : # ime se ne končna z a novSez.append(žival) return novSez
težav pa še ni konec. Vse to prekladanje seznamov je povzročilo, da so sedaj določena imena v seznamu
navedena večkrat. Zato napiši funkcijo odstraniOdvečne(seznam)
, ki vrne nov seznam, a tako, da
iz seznama pomeče
vsa odvečna imena. Pri enakih imenih ohrani le tistega, ki se je v seznamu
pojavil prvi.m Iz
['Lisko', 'Šeko', 'Šeko', 'Šeko', 'Hitri', 'Bukso', 'Lisko']
dobimo
['Lisko', 'Šeko', 'Hitri', 'Bukso']
Namig: Kaj naredi 'bla' in ['blu', 'ble', 'bla', 'blu']
?
def odstraniOdvečne(seznam): ''' vrne nov seznam brez odvečnih (podvojenih) imen ''' novSez = [] for žival in seznam: if žival not in novSez : # ime se še ni pojavilo novSez.append(žival) return novSez
Četa je najdaljše možno strnjeno podzaporedje v danem seznamu števil z določeno lastnostjo. Če je zaporedje naraščajoče (vsak naslednji element podzaporedja je večji), govorimo o naraščajočih četah, če je nepadajoče (torej je vsak naslednji element večji ali enak) o nepadajočih četah ...
Celoten seznam je tako sestavljen iz več zaporednih čet. Predpostavili bomo,
da bomo vedno upoštevali čete iste vrste. Tako v seznamu
[2,5,7,1,45,7,7,15]
najdemo kar 4 naraščajoče čete (2,5,7
, 1,45
, 7
in 7,15
),
seznam [3,5,8,10,12]
pa je sestavljen iz ene same čete.
Po drugi strani pa v seznamu
[2,5,7,1,45,7,7,15]
najdemo kar 6 padajočih čete (2
, 5
, 7, 1
, 45, 7
, 7
in 15
)
in 5 nenaraščajočih čet (2
, 5
, 7, 1
, 45, 7, 7
in 15
)
Sestavite funkcijo naraščajoč(seznam)
, ki preveri, ali elementi seznama
seznam
tvorijo narascajoče zaporedje.
>>> naraščajoč([])
True
>>> naraščajoč([1, 2, 5, 8, 12, 35])
True
>>> naraščajoč([3, 5, 5])
False
>>> naraščajoč([2, 6, 4, 8, 9, 6])
False
def naraščajoč(seznam): '''Ali vsi elementi seznama naraščajo''' if seznam == []: return True # na "prazno" res for i in range(1, len(seznam)): if seznam[i - 1] >= seznam[i]: return False return True # vse kontrole padanja so bile neuspešne, narašča!
Sestavi funkcijo številoNepadajočihČet(sez)
, ki v danem številskem seznamu prešteje, iz
koliko nepadajočih čet je sestavljen. Nepadajoča četa je najdaljši možen nepadajoče urejen
podseznam, ali še enostavneje, dokler se zaporedni elementi seznama
ne zmanjšujejo, so v isti četi.
>>> številoNepadajočihČet([])
0
>>> številoNepadajočihČet([6])
1
>>> številoNepadajočihČet([1, 3, 4, 7, 23, 56, 81])
1
>>> številoNepadajočihČet([1, 2, 2, 6, 2, 3, 7, 5, 2, 3, 8])
4
def številoNepadajočihČet(seznam): ''' koliko nepadajočih čet ima seznam ''' if seznam == []: return 0 stCet = 0 prejšni = seznam[0] # ker NE velja x < x ne bo težav z začetkom! for x in seznam: if x < prejšni: # konec čete, začetek nove stCet += 1 prejšni = x return stCet + 1 # 1 zaradi zadnje!
Sestavi funkcijo številoNaraščajočihČet(sez)
, ki v danem številskem seznamu prešteje,
iz koliko naraščajočih čet je
sestavljen. Naraščajoča četa je najdaljši možen naraščajoče urejen podseznam, ali še
enostavneje: dokler zaporedni elementi seznama naraščajo, so v isti četi.
>>> številoNaraščajočihČet([])
0
>>> številoNaraščajočihČet([6])
1
>>> številoNaraščajočihČet([1, 3, 4, 7, 23, 56, 81])
1
>>> številoNaraščajočihČet([1, 2, 2, 6, 2, 3, 7, 5, 2, 3, 8])
5
def številoNaraščajočihČet(seznam): ''' koliko naraščajočih čet ima seznam ''' if seznam == []: return 0 stCet = 0 prejšni = seznam[0] for x in seznam: if x <= prejšni: # konec čete, začetek nove stCet += 1 prejšni = x return stCet
Sestavite funkcijo dolžinaNajdaljšeNaraščajočeČete(seznam)
, ki ugotovi,
kakšna je dolžina najdaljše čete v seznamu seznam
.
>>> dolžinaNajdaljšeNaraščajočeČete([])
0
>>> dolžinaNajdaljšeNaraščajočeČete([2, 5, 7, 10])
4
>>> dolžinaNajdaljšeNaraščajočeČete([1, 3, 6, 3, 8, 8, 10, 12])
3
def dolžinaNajdaljšeNaraščajočeČete(seznam): '''Kako dolga je najdaljša naraščajoča četa''' if seznam == []: return 0 naj = 0 # največja dolžina do sedaj dolzina = 1 # dolžina trenutne čete (vsebuje prvi element) for i in range(1, len(seznam)): # od drugega elementa naprej if seznam[i - 1] < seznam[i]: dolzina += 1 # še vedno imamo isto četo else: # naleteli smo na novo četo if dolzina > naj: # je morda ravno zaključena četa daljša? naj = dolzina dolzina = 1 # začeli smo na novo return max(naj, dolzina) #paziti moramo še na dolžino zadnje
Sestavite funkcijo naraščajočeČete(seznam)
, ki vrne seznam vseh naraščajočih čet, ki tvorijo
seznam seznam
.
>>> naraščajočeČete([1, 3, 6, 3, 8, 8, 10, 12])
[[1, 3, 6], [3, 8], [8, 10, 12]]
def naraščajočeČete(seznam): '''Seznam vseh naraščajočih čet v seznamu''' if seznam == []: return [] seznamCet = [] ceta = [seznam[0]] # trenutna četa for i in range(1, len(seznam)): if seznam[i - 1] < seznam[i]: ceta.append(seznam[i]) # podaljšujemo obstoječo četo else: # zaključili smo s prejšnjo seznamCet.append(ceta) ceta = [seznam[i]] # in začeli novo seznamCet.append(ceta) # dodamo še zadnjo četo return seznamCet
Butalci vsako leto priredijo polžje dirke. Pomagajte jim pri organizaciji.
Tekmovalnega polža opišemo s tremi parametri: starostjo, težo in
velikostjo. Faktor njegove tekmovalne sposobnosti opisuje takšna formula:
Med vsemi polži želimo poiskati najboljšega. Napišite funkcijo
najboljsi(s)
, ki sprejme seznam opisov polžev (seznam trojčkov
[starost, teža, velikost]
) in vrne faktor za najboljšega polža,
spet na dve decimalni mesti natančno.
>>> najboljsi([[5, 6, 72], [4, 17, 77], [14, 21, 22], [17, 36, 64], [13, 29, 23]])
16.39
def sposobnost(s, t, v): '''Vrne sposobnost polža''' return round((s + (t/v)**2)**2,2) def najboljsi(polzi): '''Določi faktor sposobnosti najboljšega polža''' polz = polzi[0] # prvi polž najboljsiFaktor = sposobnost(polz[0], polz[1], polz[2]) # prvi je najboljši ;-) for polz in polzi: # prvega bomo sicer gledsali dvakrat, a kaj zato! kakoSposoben = sposobnost(polz[0], polz[1], polz[2]) if kakoSposoben < najboljsiFaktor: # našli smo boljšega najboljsiFaktor = kakoSposoben return najboljsiFaktor # Mimogrede: z nekaj znanja /ki ga še nimamo/ bi nalogo lahko rešili # v eni vrstici ;-) ##def najboljsi(s): ## return min([sposobnost(x[0], x[1], x[2]) for x in s])
Butalski polži se premikajo samo v štirih smereh: sever, jug, vzhod in
zahod, kar v koordinatnem sistemu pomeni gor, dol, desno in levo.
V vsakem koraku se premaknejo za eno enoto, lahko pa tudi mirujejo.
Njihove premike zato lahko opišemo s seznami, ki vsebujejo poljubno
zaporedje črk 'S'
, 'J'
, 'V'
, 'Z'
in 'M'
.
Napišite funkcijo pot(premiki)
, ki sprejme seznam, ki opisuje premike polža
in pove, kako daleč je polž lezel in kako daleč (zračne razdalje) je prilezel. Rezultat naj bo
dan v obliki para celo in dec. število, kjer je slednje zaokroženo na dve decimalni mesti.
>>> pot(['M', 'J', 'V', 'S', 'S', 'M'])
(4, 1.41)
def pot(premiki): '''Kako daleč je lezel in prilezel polž''' x=0 y=0 kolikoMirovanj = 0 for premik in premiki: # izračunamo končno točko, ter število mirovanj if premik == 'S': y += 1 elif premik == 'J': y -= 1 elif premik == 'V': x += 1 elif premik == 'Z': x -= 1 else: kolikoMirovanj += 1 kolikoLazenja = len(premiki) - kolikoMirovanj return (kolikoLazenja, round((x**2 + y**2)**0.5, 2))
Po končanem tekmovanju so znane poti vseh polžev. Velja, da je zmagovalec
tisti polž, ki je prilezel najdlje (seveda pa si lahko prvo mesto deli
več zmagovalcev, če so prelezli isto razdaljo). Pri tem seveda
doseženo razdaljo računamo zaokroženo, kot pri zg. nalogi!
Napišite funkcijo
zmagovalci(s)
, ki sprejme seznam poti vseh polžev ter izračuna, koliko
polžev je osvojilo prvo nagrado.
>>> zmagovalci([['S', 'Z', 'S'], ['M', 'Z', 'V'], ['J', 'J', 'Z'], ['J', 'J', 'Z'], ['S', 'S', 'M']])
3
def zmagovalci(poti): '''Koliko polžev je zmagalo''' najRazdalja = -1 # vse poti bodo daljše kolikoZmagovalcev = 0 for potPolza in poti: _, razdalja = pot(potPolza) # lazil nas načeloma ne zanima, zato "čudno" imen - le podčrtaj if razdalja > najRazdalja: # našli smo boljšega najRazdalja = razdalja kolikoZmagovalcev = 1 # začnemo šteti znova elif razdalja == najRazdalja: kolikoZmagovalcev += 1 # en več z naj razdaljo return kolikoZmagovalcev # # z nekaj dodatnega znanja je zapis rešitve krajši # ##def zmagovalci(s): ## p = [pot(x) for x in s] ## mx = max(p) ## return p.count(mx)